From 8c980445e3763e7a9adc25d8df1798baffaf4cdb Mon Sep 17 00:00:00 2001 From: Daniel Boles Date: Sat, 21 Jan 2017 20:23:27 +0000 Subject: [PATCH] combobox: Move area and menu to .ui file Now that priv->area is guaranteed to be constructed by us, and not passed in by a user, we can move it to the .ui file and stop manually managing its lifetime altogether. And once the area is there, we can move the menu there too (and stop pointlessly destroying/rebuilding it). --- gtk/gtkcombobox.c | 187 +++++++++--------------------------------- gtk/ui/gtkcombobox.ui | 9 ++ 2 files changed, 48 insertions(+), 148 deletions(-) diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 229f44852d..b4cfc07780 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -286,11 +286,6 @@ static void gtk_combo_box_model_row_changed (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); -/* menu */ -static void gtk_combo_box_menu_setup (GtkComboBox *combo_box); -static void gtk_combo_box_menu_destroy (GtkComboBox *combo_box); - - static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget, GdkEventButton *event, gpointer user_data); @@ -973,7 +968,14 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, box); gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, button); gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, arrow); + gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, area); + gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, popup_widget); gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_button_toggled); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_button_press); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_activate); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_key_press); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_show); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_hide); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COMBO_BOX_ACCESSIBLE); gtk_widget_class_set_css_name (widget_class, "combobox"); @@ -1001,17 +1003,30 @@ gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface) iface->start_editing = gtk_combo_box_start_editing; } +static gboolean +gtk_combo_box_row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + GtkComboBox *combo) +{ + GtkComboBoxPrivate *priv = combo->priv; + + if (priv->row_separator_func) + return priv->row_separator_func (model, iter, priv->row_separator_data); + + return FALSE; +} + static void gtk_combo_box_init (GtkComboBox *combo_box) { GtkComboBoxPrivate *priv; GtkCssNode *widget_node; GtkStyleContext *context; + GtkTreeMenu *menu; combo_box->priv = gtk_combo_box_get_instance_private (combo_box); priv = combo_box->priv; - priv->popup_widget = NULL; priv->wrap_width = 0; priv->active = -1; @@ -1033,6 +1048,7 @@ gtk_combo_box_init (GtkComboBox *combo_box) priv->id_column = -1; g_type_ensure (GTK_TYPE_ICON); + g_type_ensure (GTK_TYPE_TREE_MENU); gtk_widget_init_template (GTK_WIDGET (combo_box)); gtk_widget_add_events (priv->button, GDK_SCROLL_MASK); @@ -1048,6 +1064,17 @@ gtk_combo_box_init (GtkComboBox *combo_box) gtk_combo_box_allocate, gtk_combo_box_render, NULL, NULL); + + menu = GTK_TREE_MENU (priv->popup_widget); + _gtk_tree_menu_set_wrap_width (menu, priv->wrap_width); + _gtk_tree_menu_set_row_span_column (menu, priv->row_column); + _gtk_tree_menu_set_column_span_column (menu, priv->col_column); + _gtk_tree_menu_set_row_separator_func (menu, + (GtkTreeViewRowSeparatorFunc)gtk_combo_box_row_separator_func, + combo_box, NULL); + gtk_menu_attach_to_widget (GTK_MENU (menu), + GTK_WIDGET (combo_box), + NULL); } static void @@ -1335,17 +1362,8 @@ gtk_combo_box_remove (GtkContainer *container, gtk_widget_queue_resize (GTK_WIDGET (container)); - if (priv->popup_widget) - { - gtk_combo_box_menu_destroy (combo_box); - gtk_menu_detach (GTK_MENU (priv->popup_widget)); - priv->popup_widget = NULL; - } - gtk_combo_box_create_child (combo_box); - gtk_combo_box_menu_setup (combo_box); - if (gtk_tree_row_reference_valid (priv->active_row)) { path = gtk_tree_row_reference_get_path (priv->active_row); @@ -1385,25 +1403,6 @@ gtk_combo_box_menu_hide (GtkWidget *menu, FALSE); } -static void -gtk_combo_box_detacher (GtkWidget *widget, - GtkMenu *menu) -{ - GtkComboBox *combo_box = GTK_COMBO_BOX (widget); - GtkComboBoxPrivate *priv = combo_box->priv; - - g_return_if_fail (priv->popup_widget == (GtkWidget *) menu); - - g_signal_handlers_disconnect_by_func (menu->priv->toplevel, - gtk_combo_box_menu_show, - combo_box); - g_signal_handlers_disconnect_by_func (menu->priv->toplevel, - gtk_combo_box_menu_hide, - combo_box); - - priv->popup_widget = NULL; -} - static gboolean cell_layout_is_sensitive (GtkCellLayout *layout) { @@ -1982,91 +1981,6 @@ gtk_combo_box_scroll_event (GtkWidget *widget, return TRUE; } -/* - * menu style - */ -static gboolean -gtk_combo_box_row_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - GtkComboBox *combo) -{ - GtkComboBoxPrivate *priv = combo->priv; - - if (priv->row_separator_func) - return priv->row_separator_func (model, iter, priv->row_separator_data); - - return FALSE; -} - -static void -gtk_combo_box_menu_setup (GtkComboBox *combo_box) -{ - GtkComboBoxPrivate *priv = combo_box->priv; - GtkWidget *menu; - - g_signal_connect (priv->button, "button-press-event", - G_CALLBACK (gtk_combo_box_menu_button_press), - combo_box); - - /* create our funky menu */ - menu = _gtk_tree_menu_new_with_area (priv->area); - gtk_widget_set_name (menu, "gtk-combobox-popup-menu"); - - _gtk_tree_menu_set_model (GTK_TREE_MENU (menu), priv->model); - - _gtk_tree_menu_set_wrap_width (GTK_TREE_MENU (menu), priv->wrap_width); - _gtk_tree_menu_set_row_span_column (GTK_TREE_MENU (menu), priv->row_column); - _gtk_tree_menu_set_column_span_column (GTK_TREE_MENU (menu), priv->col_column); - - g_signal_connect (menu, "menu-activate", - G_CALLBACK (gtk_combo_box_menu_activate), combo_box); - - /* Chain our row_separator_func through */ - _gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (menu), - (GtkTreeViewRowSeparatorFunc)gtk_combo_box_row_separator_func, - combo_box, NULL); - - g_signal_connect (menu, "key-press-event", - G_CALLBACK (gtk_combo_box_menu_key_press), combo_box); - - /* Set up the popup menu */ - if (priv->popup_widget) - gtk_menu_detach (GTK_MENU (priv->popup_widget)); - - priv->popup_widget = menu; - - /* - * Note that we connect to show/hide on the toplevel, not the - * menu itself, since the menu is not shown/hidden when it is - * popped up while torn-off. - */ - g_signal_connect (GTK_MENU (menu)->priv->toplevel, "show", - G_CALLBACK (gtk_combo_box_menu_show), combo_box); - g_signal_connect (GTK_MENU (menu)->priv->toplevel, "hide", - G_CALLBACK (gtk_combo_box_menu_hide), combo_box); - - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (combo_box), - gtk_combo_box_detacher); -} - -static void -gtk_combo_box_menu_destroy (GtkComboBox *combo_box) -{ - GtkComboBoxPrivate *priv = combo_box->priv; - - g_signal_handlers_disconnect_matched (priv->button, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, - gtk_combo_box_menu_button_press, NULL); - g_signal_handlers_disconnect_matched (priv->popup_widget, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, - gtk_combo_box_menu_activate, combo_box); - - /* changing the popup window will unref the menu and the children */ -} - /* callbacks */ static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget, @@ -2221,16 +2135,8 @@ gtk_combo_box_menu_key_press (GtkWidget *widget, static GtkCellArea * gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout) { - GtkComboBox *combo = GTK_COMBO_BOX (cell_layout); - GtkComboBoxPrivate *priv = combo->priv; - - if (G_UNLIKELY (!priv->area)) - { - priv->area = gtk_cell_area_box_new (); - g_object_ref_sink (priv->area); - } - - return priv->area; + GtkComboBox *combo_box = GTK_COMBO_BOX (cell_layout); + return combo_box->priv->area; } /* @@ -2915,7 +2821,6 @@ gtk_combo_box_destroy (GtkWidget *widget) priv->box = NULL; priv->button = NULL; priv->arrow = NULL; - priv->cell_view = NULL; _gtk_bin_set_child (GTK_BIN (combo_box), NULL); } @@ -3019,18 +2924,8 @@ gtk_combo_box_constructed (GObject *object) G_OBJECT_CLASS (gtk_combo_box_parent_class)->constructed (object); - if (!priv->area) - { - priv->area = gtk_cell_area_box_new (); - g_object_ref_sink (priv->area); - } - gtk_combo_box_create_child (combo_box); - /* Create the popup menu, if it doesn’t already exist. */ - if (!priv->popup_widget) - gtk_combo_box_menu_setup (combo_box); - if (priv->has_entry) { priv->text_renderer = gtk_cell_renderer_text_new (); @@ -3041,7 +2936,6 @@ gtk_combo_box_constructed (GObject *object) } } - static void gtk_combo_box_dispose (GObject* object) { @@ -3050,17 +2944,14 @@ gtk_combo_box_dispose (GObject* object) if (priv->popup_widget) { - gtk_combo_box_menu_destroy (combo_box); + /* Stop menu destruction triggering toggle on a now-invalid button */ + g_signal_handlers_disconnect_by_func (priv->popup_widget, + gtk_combo_box_menu_hide, + combo_box); gtk_menu_detach (GTK_MENU (priv->popup_widget)); priv->popup_widget = NULL; } - if (priv->area) - { - g_object_unref (priv->area); - priv->area = NULL; - } - gtk_combo_box_unset_model (combo_box); G_OBJECT_CLASS (gtk_combo_box_parent_class)->dispose (object); diff --git a/gtk/ui/gtkcombobox.ui b/gtk/ui/gtkcombobox.ui index 2e6ac30a2b..0a8ac8ba98 100644 --- a/gtk/ui/gtkcombobox.ui +++ b/gtk/ui/gtkcombobox.ui @@ -26,6 +26,7 @@ + end @@ -34,4 +35,12 @@ + + + area + + + + + -- 2.30.2